﻿using dnlib.DotNet;
using Fixed.ILRunTime;
using ILRuntime.Runtime.CLRBinding;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEditor;
using UnityEngine;

public class CLRBinding
{
    static string[] Modules = new string[] {
            "Main",
            "HFramework"
        };
    static string[] FilterNamespace = new string[]
    {
        "huqiang.Helper.HGUI"
    };
    /// <summary>
    /// 如需使用过滤掉的类，可以新建一个类对此类进行包装，然后绑定
    /// 注意内部类格式 huqiang.UIComposite.DesignedDockAuxiliary+ItemContent
    /// </summary>
    static string[] FilterType = new string[] {
       "huqiang.IME",
       "huqiang.Data.BlockInfo",
       "huqiang.Data.MarshalBlock",
       "huqiang.Data.StructPoint",
       "huqiang.LinearTransformation",
       "huqiang_Helper_HGUI_HCanvas",

       "System.Activator",
       "System.Decimal",
       "System.RuntimeTypeHandle"
    };
    static string[] FilterMethod = new string[] {
       "huqiang.Data.FakeStructArray.get_Item",
       "huqiang.Data.FakeStructArray.set_Item",
       "huqiang.Data.FakeStruct.get_Item",
       "huqiang.Data.FakeStruct.set_Item",

       "System.Type.get_IsSZArray",
       "System.Single.IsFinite",
       "System.Double.IsFinite",
       "System.Reflection.FieldInfo.GetValueDirect",
       "System.Reflection.FieldInfo.SetValueDirect",
       "System.IO.Stream.Synchronized",
        "System.IO.Stream.Read",
       "System.IO.Stream.Write",
       "System.IO.Stream.ReadAsync",
       "System.IO.Stream.WriteAsync",
       "System.IO.FileStream..ctor",
       "System.IO.FileStream.GetAccessControl",
       "System.IO.FileStream.SetAccessControl"
    };
    static string[] FilterField= new string[] {
        "huqiang.Data.FakeStruct.ip",
        "huqiang.Data.FakeStructArray.ip"
    };
    /// <summary>
    /// 添加自定义类型
    /// </summary>
    /// <param name="tmpList"></param>
    //static void CollectionCustomType(List<string> tmpList)
    //{
    //    /// 注意内部类格式 huqiang.UIComposite.DesignedDockAuxiliary+ItemContent
    //}
    /// <summary>
    /// 添加自定义类型
    /// </summary>
    /// <param name="tmpList"></param>
    static void CollectionCustomType(List<Type> types)
    {
        types.Add(typeof(UnityEngine.Vector2));
        types.Add(typeof(UnityEngine.Vector3));
        types.Add(typeof(UnityEngine.Vector4));
        types.Add(typeof(UnityEngine.Quaternion));
        types.Add(typeof(UnityEngine.Color));
        types.Add(typeof(UnityEngine.Color32));

        types.Add(typeof(UnityEngine.Transform));
        types.Add(typeof(UnityEngine.GameObject));
        types.Add(typeof(UnityEngine.Camera));
    }
    static void CollectionFromDll(List<string> tmpList)
    {
        string dllpath = @"Library\ScriptAssemblies\HotFix.dll";
        if (File.Exists(dllpath))
        {
            ModuleContext modCtx = ModuleDef.CreateModuleContext();
            ModuleDefMD module = ModuleDefMD.Load(dllpath, modCtx);
            var types = module.GetTypeRefs();
            foreach (var i in types)
            {
                string name = i.FullName;
                string np = i.Namespace.String;
                if (!FilterNamespace.Contains(np))
                    if (name.IndexOf('`') < 0)
                    {
                        name = name.Replace('/', '+');
                        if (!FilterType.Contains(name))
                            if (!tmpList.Contains(name))
                                tmpList.Add(name);
                    }
            }
        }
    }
    static void CollectionFromHGUI(List<string> tmpList, Assembly ass)
    {
        var arry = ass.GetExportedTypes();
        for (int i = 0; i < arry.Length; i++)
        {
            if (arry[i].IsPublic)
            {
                var np = arry[i].Namespace;
                if (np != null)
                    if (np.IndexOf("huqiang") == 0)
                    {
                        if (!FilterNamespace.Contains(np))
                            if (arry[i].Name.IndexOf('`') < 0)
                            {
                                string name = np + "." + arry[i].Name;
                                if (!FilterType.Contains(name))
                                    if (!tmpList.Contains(name))
                                        tmpList.Add(name);
                            }
                    }
            }
        }
    }
    static void CollectionFromAssembly(List<string> tmpList, Assembly ass)
    {
        var arry = ass.GetExportedTypes();
        for (int i = 0; i < arry.Length; i++)
        {
            if (arry[i].IsPublic)
            {
                string name = arry[i].Name;
                var np = arry[i].Namespace;
                if (name.IndexOf('`') < 0&&name.IndexOf('/')<0)
                {
                    if (np != null && np != "")
                        name = np + "." + name;
                    if (!FilterType.Contains(name))
                        if (!tmpList.Contains(name))
                            tmpList.Add(name);
                }
            }
        }
    }
    [MenuItem("ILRuntime/一键生成绑定代码")]
    public static void CreateBinding()
    {
        BindingGeneratorExtensions.FilterMethod = FilterMethod;
        BindingGeneratorExtensions.FilterField = FilterField;
        List<string> types = new List<string>();
        List<Type> tmp = new List<Type>();
        CollectionCustomType(tmp);
        for (int i = 0; i < tmp.Count; i++)
            types.Add(tmp[i].FullName);

        Assembly[] AssbyList = AppDomain.CurrentDomain.GetAssemblies();
        int c = types.Count;
        for (int i = 0; i < AssbyList.Length; i++)
        {
            string name = AssbyList[i].GetName().Name;
            if (Modules.Contains(name))
            {
                CollectionFromAssembly(types, AssbyList[i]);
                for (int j = c; j < types.Count; j++)
                {
                    tmp.Add(AssbyList[i].GetType(types[j]));
                }
                c = types.Count;
            }
            else if (name == "HGUI")
            {
                CollectionFromHGUI(types, AssbyList[i]);
                for (int j = c; j < types.Count; j++)
                {
                    tmp.Add(AssbyList[i].GetType(types[j]));
                }
                c = types.Count;
            }
        }
        c = types.Count;
        CollectionFromDll(types);
        for (int i = c; i < types.Count; i++)
        {
            for (int j = 0; j < AssbyList.Length; j++)
            {
                var type = AssbyList[j].GetType(types[i]);
                if (type != null)
                {
                    tmp.Add(type);
                    goto label;
                }
            }
            Debug.Log(types[i]);
            label:;
        }
        string saveFolder = "Assets/GameScripts/ILBinding";
        FileHelper.DeleteDirectory(saveFolder);
        Directory.CreateDirectory(saveFolder);
        try
        {
            ILRuntime.Runtime.CLRBinding.BindingCodeGenerator.GenerateBindingCode(tmp, saveFolder);
        }
        catch (Exception ex)
        {
            Debug.Log(ex.Message);
        }
        AssetDatabase.Refresh();
    }

    //[MenuItem("ILRuntime/生成绑定类型")]
    //public static void MakeAllType()
    //{
    //    List<string> types = new List<string>();
    //    CollectionCustomType(types);
    //    Assembly[] AssbyList = AppDomain.CurrentDomain.GetAssemblies();
    //    for (int i = 0; i < AssbyList.Length; i++)
    //    {
    //        string name = AssbyList[i].GetName().Name;
    //        if (Modules.Contains(name))
    //            CollectionFromAssembly(types, AssbyList[i]);
    //        else if (name == "HGUI")
    //            CollectionFromHGUI(types, AssbyList[i]);
    //    }
    //    CollectionFromDll(types);
    //    StringBuilder sb = new StringBuilder();
    //    sb.Append("using System;\nusing System.Collections.Generic;\n public class BindingTypes\n{  \n     public static List<Type> CreateBiding()\n{\n        List<Type> types = new List<Type>();\n");
    //    for (int i = 0; i < types.Count; i++)
    //    {
    //        sb.Append("        types.Add(typeof(");
    //        sb.Append(types[i].Replace('+', '.'));
    //        sb.Append("));\n");
    //    }
    //    sb.Append("        return types;\n    }\n}");
    //    string savePath = "Assets/GameScripts/HFramework/Editor/BindingTypes.cs";
    //    if (File.Exists(savePath))
    //        File.Delete(savePath);
    //    File.WriteAllText(savePath, sb.ToString());
    //    AssetDatabase.Refresh();
    //}
    //[MenuItem("ILRuntime/生成绑定代码")]
    //public static void CreateTypeBinding()
    //{
    //    BindingGeneratorExtensions.FilterMethod = FilterMethod;
    //    BindingGeneratorExtensions.FilterField = FilterField;
    //    string saveFolder = "Assets/GameScripts/ILBinding";
    //    FileHelper.DeleteDirectory(saveFolder);
    //    Directory.CreateDirectory(saveFolder);

    //    try
    //    {
    //        var tmp = BindingTypes.CreateBiding();
    //        ILRuntime.Runtime.CLRBinding.BindingCodeGenerator.GenerateBindingCode(tmp, saveFolder);
    //    }
    //    catch (Exception ex)
    //    {
    //        Debug.Log(ex.StackTrace);
    //    }
    //    AssetDatabase.Refresh();
    //}
}
